<template>
  <AppPage show-footer>
    <!-- 用户信息与欢迎区 -->
    <div class="flex">
      <n-card class="min-w-200 w-30%">
        <div class="flex items-center">
          <n-avatar round :size="60" :src="userStore.avatar" class="flex-shrink-0" />
          <div class="ml-20 flex-col">
            <span class="text-20 opacity-80">
              Hello, {{ userStore.nickName ?? userStore.username }}
            </span>
            <span class="mt-4 opacity-50">当前角色：{{ userStore.currentRole?.name }}</span>
          </div>
        </div>
        <p class="mt-28 text-14 opacity-60">
          "得不到的永远在骚动，被偏爱的都有恃无恐" —— 《红玫瑰》陈奕迅
        </p>
      </n-card>

      
      <!-- 欢迎与系统简介 -->
      <n-card class="ml-12 w-70%" title="✨ 欢迎使用分镜生成系统">
        <p class="opacity-60">
          欢迎来到我们的分镜生成应用！通过上传歌词和描述，你将能够生成一系列相关且连贯的分镜图像，帮助你更好地实现创作的灵感。
        </p>
        <footer class="mt-12 flex items-center justify-end">
          <n-button
            type="primary"
            ghost
            tag="a"
            href="https://your-doc-link.com"
            target="__blank"
          >
            查看文档
          </n-button>
        </footer>
      </n-card>
    </div>

    <div class="flex mt-16 gap-4">
       <!-- 歌曲选择与歌词展示 -->
       <n-card class="w-50%" title="🎶 选择歌曲" segmented>
        <p class="text-14 opacity-60">上传一首歌曲，我们将为你展示歌词并生成分镜。</p>

        <n-divider class="mt-8" />

        <!-- 新增：歌词输入区域 -->
        <div class="mt-8">
          <h3 class="text-16 opacity-80 mb-4">直接输入歌词：</h3>
          <n-input
            v-model:value="manualLyrics"
            type="textarea"
            :autosize="{ minRows: 6, maxRows: 10 }"
            placeholder="在此输入歌词内容..."
            class="mb-4"
          />
        </div>

        <!-- 歌词操作按钮组 -->
        <div class="flex gap-4 mt-4">
          <n-button type="primary" @click="useManualLyrics" :disabled="!manualLyrics.trim()">
            開始生成分鏡
          </n-button>
          <n-button @click="triggerFileInput">
            选择本地歌词文件
          </n-button>
        </div>

        <!-- 隐藏的文件输入框 -->
        <input ref="fileInput" type="file"  accept=".txt,.json" @change="handleFileChange" />

        <!-- 关键词选择区域 -->
        <div class="mt-16">
          <h3 class="text-16 opacity-80 mb-4">添加关键词</h3>
          <div class="flex gap-2">
            <n-select
              v-model:value="selectedKeywords"
              multiple
              filterable
              tag
              :options="presetKeywords"
              placeholder="选择或输入关键词"
              @create="handleKeywordCreate"
              style="flex: 1"
            />
            <n-button @click="clearKeywords" secondary>
              清空
            </n-button>
          </div>
          <div v-if="selectedKeywords.length > 0" class="mt-4">
            <n-tag
              v-for="(keyword, index) in selectedKeywords"
              :key="index"
              closable
              @close="removeKeyword(index)"
              class="mr-2 mb-2"
            >
              {{ keyword }}
            </n-tag>
          </div>
        </div>


        <!-- 上传图片区域 -->
         <div class="mt-8">
  <h3 class="text-16 opacity-80 mb-2">上传风格图片</h3>
  
  <!-- 图片预览 -->
  <div class="flex flex-wrap gap-4 mt-4">
    <!-- 图片展示 -->
    <div
      v-for="(image, index) in styleImages"
      :key="image.id"
      class="relative w-[100px] h-[100px] border rounded overflow-hidden"
    >
      <n-image
        :src="image.url"
        width="100"
        height="100"
        object-fit="cover"
      />
      <!-- 删除按钮 -->
      <n-button
        quaternary
        type="error"
        size="small"
        class="absolute top-0 right-0 z-10"
        @click.stop="removeImage(index)"
      >
        ✕
      </n-button>
    </div>
    


  </div>


  <!-- 上传按钮 -->
  <n-upload
    :show-file-list="false"
    :custom-request="handleImageUpload"
    accept="image/*"
    multiple
  >
    <n-button dashed type="primary">选择图片上传</n-button>
  </n-upload>

<!-- 图片预览 + 拖拽排序 -->





  </div>
      </n-card>


      <!-- 分镜展示区 -->
      <n-card class="ml-12 w-60%" title="📸 生成的分镜" segmented>
        <div class="flex items-center justify-between mb-4">
          <p class="opacity-60">
            在这里展示由歌词生成的分镜图像
          </p>
          <n-radio-group v-model:value="displayMode" size="small">
            <n-radio-button value="slide">左右切换</n-radio-button>
            <n-radio-button value="drag">拖动浏览</n-radio-button>
          </n-radio-group>
        </div>

        <!-- 图片展示区域 -->
        <div class="relative overflow-hidden" :style="{ height: '600px' }">
          <!-- 左右切换模式 -->
          <div 
            v-if="displayMode === 'slide'"
            class="flex items-center h-full transition-transform duration-300"
            :style="{ transform: `translateX(-${currentIndex * 100}%)` }"
          >
            <div 
              v-for="(image, index) in storyboardImages" 
              :key="index"
              class="flex-shrink-0 w-full h-full flex items-center justify-center relative"
            >

            <n-tooltip placement="top" :width="240">
              <template #trigger>
              <n-image
                :src="image.url"
                :alt="`分镜 ${index + 1}`"
                 class="max-h-full max-w-full object-contain block"
                 :preview-disabled="true"
                />
              </template>
            <div>
              <strong>{{ image.title }}</strong><br />
              <span>{{ image.description || '暂无描述' }}</span>
            </div>
            </n-tooltip>
              <div class="absolute bottom-10 left-1/2 -translate-x-1/2 text-center">
                <n-input
                  v-model:value="image.title"
                  placeholder="编辑标题"
                  size="small"
                  class="text-center w-60"
                />
              </div>
            </div>
          </div>

          <!-- 拖动浏览模式（结构略同） -->
          <div 
            v-else
            ref="scrollContainer"
            class="flex h-full overflow-x-auto overflow-y-hidden"
            @wheel.prevent="handleWheelScroll"
          >
            <div 
              v-for="(image, index) in storyboardImages" 
              :key="index"
              class="flex-shrink-0 w-full h-full flex items-center justify-center relative"
            >
      
            <n-tooltip placement="top" :width="240">
          <template #trigger>
          <n-image
            :src="image.url"
            :alt="`分镜 ${index + 1}`"
            class="max-h-full max-w-full object-contain cursor-pointer"
            :preview-disabled="true"
          />
        </template>
        <div>
          <strong>{{ image.title }}</strong><br />
          <span>{{ image.description || '暂无描述' }}</span>
        </div>
      </n-tooltip>
              <div class="absolute bottom-10 left-1/2 -translate-x-1/2 text-center">
                <n-input
                  v-model:value="image.title"
                  placeholder="编辑标题"
                  size="small"
                  class="text-center w-60"
                />
              </div>
            </div>
          </div>

          <!-- 导航箭头 -->
          <template v-if="storyboardImages.length > 1">
            <div 
              class="absolute left-2 top-1/2 -translate-y-1/2 bg-white bg-opacity-70 rounded-full p-2 cursor-pointer hover:bg-opacity-100 transition"
              @click="prevImage"
            >
              <n-icon size="24">
                <ChevronBack />
              </n-icon>
            </div>
            <div 
              class="absolute right-2 top-1/2 -translate-y-1/2 bg-white bg-opacity-70 rounded-full p-2 cursor-pointer hover:bg-opacity-100 transition"
              @click="nextImage"
            >
              <n-icon size="24">
                <ChevronForward />
              </n-icon>
            </div>
          </template>
        </div>

         <!-- 缩略图导航 -->
         <div v-if="storyboardImages.length > 1" class="flex overflow-x-auto py-2 mt-4 gap-2">
          <div 
            v-for="(image, index) in storyboardImages"
            :key="index"
            class="flex-shrink-0 w-16 h-16 cursor-pointer border-2 rounded"
            :class="{ 'border-blue-500': currentIndex === index, 'border-transparent': currentIndex !== index }"
            @click="currentIndex = index"
          >
            <n-image
              :src="image.url"
              class="w-full h-full object-cover"
              :preview-disabled="true"
            />
          </div>
        </div>

        <!-- 导出按钮 -->
        <div class="mt-4 flex justify-end">
          <n-button type="success" @click="exportStoryboard">
            导出 JSON
          </n-button>
          <n-button type="info" @click="exportAsImage">
            导出为图片
          </n-button>
          <n-button type="warning" @click="exportAsPDF">
            导出为 PDF
          </n-button>
        </div>
      </n-card>
    </div>

    <!-- 错误提示框 -->
    <n-alert v-if="errorMessage" type="error" class="mt-12" show-icon>
      {{ errorMessage }}
    </n-alert>
  </AppPage>
</template>

<script setup>
import { useUserStore } from '@/store'
import { useRouter } from 'vue-router'
import { ref } from 'vue'
import { ChevronBack, ChevronForward } from '@vicons/ionicons5'
import api from '@/api'
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
import draggable from 'vuedraggable'
import { nanoid } from 'nanoid' // 安装 nanoid: npm i nanoid


// 展示模式：slide(左右切换) 或 drag(拖动浏览)
const displayMode = ref('slide')
// 分镜图片数据（模拟API获取）
const storyboardImages = ref([])
// 当前显示索引
const currentIndex = ref(0)
// 新增：手动输入的歌词
const manualLyrics = ref('')
const selectedSongLyrics = ref("")
const errorMessage = ref("")
const selectedKeywords = ref([])
const userStore = useUserStore()
const router = useRouter()
const fileInput = ref(null)


//export storyboard
const exportStoryboard = () => {
  const data = storyboardImages.value.map(({ url, title }) => ({ url, title }))
  const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' })
  const link = document.createElement('a')
  link.href = URL.createObjectURL(blob)
  link.download = 'storyboard.json'
  link.click()
  URL.revokeObjectURL(link.href)
}
const exportAsImage = async () => {
   const images = await Promise.all(
    storyboardImages.value.map(({ url }) => {
      return new Promise((resolve) => {
        const img = new Image()
        img.crossOrigin = 'anonymous'
        img.src = url
        img.onload = () => resolve(img)
      })
    })
  )

  const width = 800
  const padding = 20
  const titleHeight = 40
  const fontSize = 20

  // 计算总高度：标题 + 图像 + 间距
  let totalHeight = 0
  storyboardImages.value.forEach((img, index) => {
    const h = (width / images[index].width) * images[index].height
    totalHeight += h + titleHeight + padding
  })

  const canvas = document.createElement('canvas')
  canvas.width = width
  canvas.height = totalHeight
  const ctx = canvas.getContext('2d')

  ctx.fillStyle = '#ffffff'
  ctx.fillRect(0, 0, canvas.width, canvas.height)

  ctx.fillStyle = '#000000'
  ctx.font = `${fontSize}px sans-serif`
  ctx.textAlign = 'center'

  let offsetY = 0
  images.forEach((img, index) => {
    const title = storyboardImages.value[index].title || `分镜 ${index + 1}`
    ctx.fillText(title, width / 2, offsetY + fontSize)

    offsetY += titleHeight
    const h = (width / img.width) * img.height
    ctx.drawImage(img, 0, offsetY, width, h)

    offsetY += h + padding
  })

  const link = document.createElement('a')
  link.href = canvas.toDataURL('image/png')
  link.download = 'storyboard-with-titles.png'
  link.click()
}


const exportAsPDF = async () => {
  if (!storyboardImages.value.length) return
  const pdf = new jsPDF('p', 'mm', 'a4')
  const pageWidth = pdf.internal.pageSize.getWidth()
  const pageHeight = pdf.internal.pageSize.getHeight()

  for (let i = 0; i < storyboardImages.value.length; i++) {
    const { url, title } = storyboardImages.value[i]
    const img = new Image()
    img.crossOrigin = 'anonymous'
    img.src = url

    await new Promise((resolve) => {
      img.onload = () => {
        const aspectRatio = img.width / img.height
        const imgWidth = pageWidth
        const imgHeight = imgWidth / aspectRatio

        const imageY = 30 // 下移一点，留出标题
        const textY = 15

        // 添加标题
        pdf.setFontSize(16)
        pdf.text(title || `分镜 ${i + 1}`, pageWidth / 2, textY, { align: 'center' })

        // 添加图像
        pdf.addImage(img, 'PNG', 0, imageY, imgWidth, imgHeight)
        if (i < storyboardImages.value.length - 1) pdf.addPage()
        resolve()
      }
    })
  }

  pdf.save('storyboard-with-titles.pdf')
}


const styleImages = ref([
  
])



// 上传参考图
const handleImageUpload = (options) => {
  const rawFile = options.file?.file
  if (!rawFile || !(rawFile instanceof File)) {
   $message.error('请选择有效的图片文件')
    options.onError()
    return
  }

  const reader = new FileReader()
 
  reader.readAsDataURL(rawFile)

  reader.onload = () => {
    const newImage = {
      id: nanoid(),
      name: rawFile.name,
      url: reader.result
    }
    // 关键修改：检查是否已存在相同文件
    const exists = styleImages.value.some(img => 
      img.name === newImage.name && img.size === rawFile.size
    )
    
    if (!exists) {
      styleImages.value = [...styleImages.value, newImage]
      $message.success(`上传成功：${rawFile.name}`)
      if (typeof options.onSuccess === 'function') options.onSuccess()
    }else {
      $message.warning(`图片已存在：${rawFile.name}`)
      if (typeof options.onError === 'function') options.onError()
    }
  

  }
  
  reader.onerror = options.onError
  //reader.readAsDataURL(rawFile)
  

  reader.onerror = () => {
   $message.error('图片读取失败')
    options.onError()
  }

}

const removeImage = (index) => {
  styleImages.value.splice(index, 1)
  $message.info('已删除图片')
}


// 导航方法
const prevImage = () => {
  currentIndex.value = (currentIndex.value - 1 + storyboardImages.value.length) % storyboardImages.value.length
}

const nextImage = () => {
  currentIndex.value = (currentIndex.value + 1) % storyboardImages.value.length
}

// 横向滚动处理
const handleWheelScroll = (e) => {
  if (displayMode.value !== 'drag') return
  const container = e.currentTarget
  container.scrollLeft += e.deltaY
}


// 预设关键词
const presetKeywords = [
  { label: '浪漫', value: '浪漫' },
  { label: '悲伤', value: '悲伤' },
  { label: '欢乐', value: '欢乐' },
  { label: '怀旧', value: '怀旧' },
  { label: '未来感', value: '未来感' },
  { label: '复古', value: '复古' },
  { label: '城市', value: '城市' },
  { label: '自然', value: '自然' },
]
// 新增：使用手动输入的歌词
const useManualLyrics = () => {
  if (manualLyrics.value && manualLyrics.value.trim()) {
    selectedSongLyrics.value = manualLyrics.value.trim(); 
    errorMessage.value = '';
    generateStoryboardHandler()
  } else {
    errorMessage = '请输入有效的歌词内容'
  }
}

// 触发文件选择对话框
const triggerFileInput = () => {
  fileInput.value.click()
  generateStoryboardHandler()
}

// 处理文件选择
const handleFileChange = (event) => {
  
  const file = event.target.files[0]
  if (file) {
    const fileExtension = file.name.split('.').pop().toLowerCase()
    // 校验文件类型
    if (fileExtension !== 'txt' && fileExtension !== 'json') {

      errorMessage.value = '请选择一个有效的歌词文件 (.txt 或 .json)'
      $message.error("请上传正确的文件")
      return
    }
    // 重置错误信息
    errorMessage.value = ''
    const reader = new FileReader()
    reader.readAsText(file)
    reader.onload = function (e) {
      $message.loading("1"); // 开始加载提示

      const fileContent = e.target.result;
      manualLyrics.value = fileContent;
      // 如果是 JSON 格式，尝试解析并提取歌词
      if (fileExtension === 'json') {
        try {
          const parsedContent = JSON.parse(fileContent);
          manualLyrics.value = parsedContent.lyrics || '无法读取歌词内容';
        } catch (error) {
          errorMessage.value = '解析JSON文件失败，请确保文件格式正确';
          $message.error("解析JSON文件失败，请确保文件格式正确");
        }
      }

      // 加载完成后关闭提示
      $message.destroy("1");
    }

    reader.onerror = function (error) {
      console.error("文件读取失败:", error);
      $message.error("文件读取失败，请重试");
      errorMessage.value = '文件读取失败，请重试';
    }

    
  }
}

// 添加自定义关键词
const handleKeywordCreate = (keyword) => {
  selectedKeywords.value.push(keyword)
  return keyword
}

// 移除关键词
const removeKeyword = (index) => {
  selectedKeywords.value.splice(index, 1)
}

// 清空所有关键词
const clearKeywords = () => {
  selectedKeywords.value = []
}
const generateStoryboardHandler = async () => {
  if (!selectedSongLyrics.value || !selectedSongLyrics.value.trim()) {
    errorMessage.value = '請先輸入或上傳歌詞'
    return
  }

  try {
    errorMessage.value = ''
    console.log("传给后端的歌词：", selectedSongLyrics.value);
    console.log("传给后端的关键词：", selectedKeywords.value);
    console.log("传给后端的图片：", styleImages.value);
    // Clear previous images while loading new ones
    storyboardImages.value = []
    
    const res = await api.LyricsPush({
      lyrics: selectedSongLyrics.value,
      keywords: selectedKeywords.value,
      images:styleImages.value

    })

    const result = res.data
    
    // Assuming the backend returns an array of image objects with url and title
    if (Array.isArray(result)) {
      storyboardImages.value = result.map((img, index) => ({
        url: img.url || '', // Ensure url exists
        title: img.title || `分鏡 ${index + 1}`, // Default title if not provided
        description:img.description
      }))
    } else if (result) {
      // If it's a single image object
      storyboardImages.value = [{
        url: result.url || '',
        title: result.title || '分鏡 1'
      }]
    } else {
      storyboardImages.value = []
    }
    
    console.log("返回：", storyboardImages.value);
    
    if (storyboardImages.value.length === 0) {
      errorMessage.value = '生成失敗，後端未返回圖片'
    } else {
      currentIndex.value = 0
    }
  } catch (err) {
    console.error('生成分鏡錯誤：', err)
    errorMessage.value = '分鏡生成失敗，請稍後再試'
    // Clear images on error
    storyboardImages.value = []
  }
}

</script>

<style scoped>
.hidden {
  display: none;
}
img {
  user-select: none;
  -webkit-user-drag: none;
}
</style>
